import { Model, DataTypes, Optional } from 'sequelize';
import sequelize from '@/config/database';
import Role from './role.model';

// 定义菜单属性接口
interface MenuAttributes {
  menuId: number;
  menuName: string;
  parentId?: number;
  orderNum?: number;
  path?: string;
  component?: string;
  query?: string;
  routeName?: string;
  isFrame?: number;
  isCache?: number;
  menuType?: string;
  visible?: string;
  status?: string;
  perms?: string;
  icon?: string;
  createBy?: string;
  createTime?: Date;
  updateBy?: string;
  updateTime?: Date;
  remark?: string;
}

// 创建时可选的字段
interface MenuCreationAttributes extends Optional<MenuAttributes, 'menuId'> {}

// 菜单模型类
class Menu extends Model<MenuAttributes, MenuCreationAttributes> implements MenuAttributes {
  public menuId!: number;
  public menuName!: string;
  public parentId?: number;
  public orderNum?: number;
  public path?: string;
  public component?: string;
  public query?: string;
  public routeName?: string;
  public isFrame?: number;
  public isCache?: number;
  public menuType?: string;
  public visible?: string;
  public status?: string;
  public perms?: string;
  public icon?: string;
  public createBy?: string;
  public createTime?: Date;
  public updateBy?: string;
  public updateTime?: Date;
  public remark?: string;

  // 时间戳
  public readonly createdAt!: Date;
  public readonly updatedAt!: Date;

  // 检查菜单状态是否正常
  public isActive(): boolean {
    return (this.status === '0' || this.status === undefined) && 
           (this.visible === '0' || this.visible === undefined);
  }

  // 判断是否为目录
  public isDirectory(): boolean {
    return this.menuType === 'M';
  }

  // 判断是否为菜单
  public isMenu(): boolean {
    return this.menuType === 'C';
  }

  // 判断是否为按钮
  public isButton(): boolean {
    return this.menuType === 'F';
  }

  // 获取子菜单
  public static async getChildrenMenus(parentId: number): Promise<Menu[]> {
    return await Menu.findAll({
      where: {
        parentId,
        status: '0'
      },
      order: [['orderNum', 'ASC']]
    });
  }
}

Menu.init(
	{
		menuId: {
			type: DataTypes.BIGINT,
			primaryKey: true,
			autoIncrement: true,
			field: "menu_id",
			get() {
				const value = this.getDataValue("menuId");
				return value !== undefined ? Number(value) : undefined;
			},
		},
		menuName: {
			type: DataTypes.STRING(50),
			allowNull: false,
			field: "menu_name",
		},
		parentId: {
			type: DataTypes.BIGINT,
			defaultValue: 0,
			field: "parent_id",
			get() {
				const value = this.getDataValue("parentId");
				return value !== undefined ? Number(value) : undefined;
			},
		},
		orderNum: {
			type: DataTypes.INTEGER,
			defaultValue: 0,
			field: "order_num",
			get() {
				const value = this.getDataValue("orderNum");
				return value !== undefined ? Number(value) : undefined;
			},
		},
		path: {
			type: DataTypes.STRING(200),
			defaultValue: "",
			field: "path",
		},
		component: {
			type: DataTypes.STRING(255),
			defaultValue: null,
			field: "component",
		},
		query: {
			type: DataTypes.STRING(255),
			defaultValue: null,
			field: "query",
		},
		routeName: {
			type: DataTypes.STRING(50),
			defaultValue: "",
			field: "route_name",
		},
		isFrame: {
			type: DataTypes.TINYINT,
			field: "is_frame",
			defaultValue: 1,
			get() {
				const value = this.getDataValue("isFrame");
				return value !== undefined ? String(value) : undefined;
			},
			set(value: string | number) {
				if (value !== undefined) {
					this.setDataValue(
						"isFrame",
						typeof value === "string" ? parseInt(value, 10) : value
					);
				}
			},
		},
		isCache: {
			type: DataTypes.TINYINT,
			field: "is_cache",
			defaultValue: 0,
			get() {
				const value = this.getDataValue("isCache");
				return value !== undefined ? String(value) : undefined;
			},
			set(value: string | number) {
				if (value !== undefined) {
					this.setDataValue(
						"isCache",
						typeof value === "string" ? parseInt(value, 10) : value
					);
				}
			},
		},
		menuType: {
			type: DataTypes.CHAR(1),
			defaultValue: "",
			field: "menu_type",
		},
		visible: {
			type: DataTypes.CHAR(1),
			defaultValue: "0",
			field: "visible",
		},
		status: {
			type: DataTypes.CHAR(1),
			defaultValue: "0",
			field: "status",
		},
		perms: {
			type: DataTypes.STRING(100),
			defaultValue: null,
			field: "perms",
		},
		icon: {
			type: DataTypes.STRING(100),
			defaultValue: "#",
			field: "icon",
		},
		createBy: {
			type: DataTypes.STRING(64),
			defaultValue: "",
			field: "create_by",
		},
		createTime: {
			type: DataTypes.DATE,
			field: "create_time",
		},
		updateBy: {
			type: DataTypes.STRING(64),
			defaultValue: "",
			field: "update_by",
		},
		updateTime: {
			type: DataTypes.DATE,
			field: "update_time",
		},
		remark: {
			type: DataTypes.STRING(500),
			defaultValue: "",
			field: "remark",
		},
	},
	{
		sequelize,
		tableName: 'sys_menu',
		timestamps: true,
		createdAt: 'createTime',
		updatedAt: 'updateTime',
	}
);

// 导入关联在roleMenu.model.ts中定义，但需要在这里定义别名
Menu.belongsToMany(Role, {
  through: 'sys_role_menu',
  foreignKey: 'menu_id',
  otherKey: 'role_id',
  as: 'Roles'
});

export default Menu;